/*
 * Copyright (c) 2017 Intel Corporation
 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT espressif_esp32_i2c

/* Include esp-idf headers first to avoid redefining BIT() macro */
#include <soc/i2c_reg.h>
#include <esp32/rom/gpio.h>
#include <soc/gpio_sig_map.h>
#include <hal/i2c_ll.h>
#include <hal/i2c_hal.h>
#include <hal/gpio_hal.h>

#include <soc.h>
#include <errno.h>
#include <drivers/gpio.h>
#include <drivers/i2c.h>
#include <drivers/interrupt_controller/intc_esp32.h>
#include <drivers/clock_control.h>
#include <sys/util.h>
#include <string.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(i2c_esp32, CONFIG_I2C_LOG_LEVEL);

#include "i2c-priv.h"

#define I2C_FILTER_CYC_NUM_DEF 7	/* Number of apb cycles filtered by default */
#define I2C_CLR_BUS_SCL_NUM 9	/* Number of SCL clocks to restore SDA signal */
#define I2C_CLR_BUS_HALF_PERIOD_US 5	/* Period of SCL clock to restore SDA signal */
#define I2C_TRANSFER_TIMEOUT_MSEC 500	/* Transfer timeout period */

/* Freq limitation when using different clock sources */
#define I2C_CLK_LIMIT_REF_TICK (1 * 1000 * 1000 / 20)	/* REF_TICK, no more than REF_TICK/20*/
#define I2C_CLK_LIMIT_APB (80 * 1000 * 1000 / 20)	/* Limited by APB, no more than APB/20 */
#define I2C_CLK_LIMIT_RTC (20 * 1000 * 1000 / 20)	/* Limited by RTC, no more than RTC/20 */
#define I2C_CLK_LIMIT_XTAL (40 * 1000 * 1000 / 20)	/* Limited by RTC, no more than XTAL/20 */

enum i2c_status_t {
	I2C_STATUS_READ,	/* read status for current master command */
	I2C_STATUS_WRITE,	/* write status for current master command */
	I2C_STATUS_IDLE,	/* idle status for current master command */
	I2C_STATUS_ACK_ERROR,	/* ack error status for current master command */
	I2C_STATUS_DONE,	/* I2C command done */
	I2C_STATUS_TIMEOUT,	/* I2C bus status error, and operation timeout */
};

struct i2c_esp32_pin {
	const char *gpio_name;
	int sig_out;
	int sig_in;
	gpio_pin_t pin;
};

struct i2c_esp32_data {
	i2c_hal_context_t hal;
	struct k_sem cmd_sem;
	struct k_sem transfer_sem;
	volatile enum i2c_status_t status;
	uint32_t dev_config;
	int cmd_idx;
	int irq_line;

	const struct device *scl_gpio;
	const struct device *sda_gpio;
};

typedef void (*irq_connect_cb)(void);

struct i2c_esp32_config {
	int index;

	const struct device *clock_dev;

	const struct i2c_esp32_pin scl;
	const struct i2c_esp32_pin sda;

	const clock_control_subsys_t clock_subsys;

	const struct {
		bool tx_lsb_first;
		bool rx_lsb_first;
	} mode;

	int irq_source;

	const uint32_t default_config;
	const uint32_t bitrate;
};

/* I2C clock characteristic, The order is the same as i2c_sclk_t. */
static uint32_t i2c_clk_alloc[I2C_SCLK_MAX] = {
	0,
#if SOC_I2C_SUPPORT_APB
	I2C_CLK_LIMIT_APB,	/* I2C APB clock characteristic */
#endif
#if SOC_I2C_SUPPORT_XTAL
	I2C_CLK_LIMIT_XTAL,	/* I2C XTAL characteristic */
#endif
#if SOC_I2C_SUPPORT_RTC
	I2C_CLK_LIMIT_RTC,	/* I2C 20M RTC characteristic */
#endif
#if SOC_I2C_SUPPORT_REF_TICK
	I2C_CLK_LIMIT_REF_TICK,	/* I2C REF_TICK characteristic */
#endif
};

static i2c_sclk_t i2c_get_clk_src(uint32_t clk_freq)
{
	for (i2c_sclk_t clk = I2C_SCLK_DEFAULT + 1; clk < I2C_SCLK_MAX; clk++) {
		if (clk_freq <= i2c_clk_alloc[clk]) {
			return clk;
		}
	}
	return I2C_SCLK_MAX;	/* flag invalid */
}

static int i2c_esp32_config_pin(const struct device *dev)
{
	const struct i2c_esp32_config *config = dev->config;
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	int ret = 0;

	if (config->index >= SOC_I2C_NUM) {
		LOG_ERR("Invalid I2C peripheral number");
		return -EINVAL;
	}

	gpio_pin_set(data->sda_gpio, config->sda.pin, 1);
	ret = gpio_pin_configure(data->sda_gpio, config->sda.pin,
			GPIO_PULL_UP | GPIO_OPEN_DRAIN | GPIO_OUTPUT | GPIO_INPUT);
	esp_rom_gpio_matrix_out(config->sda.pin, config->sda.sig_out, 0, 0);
	esp_rom_gpio_matrix_in(config->sda.pin, config->sda.sig_in, 0);

	gpio_pin_set(data->scl_gpio, config->scl.pin, 1);
	ret |= gpio_pin_configure(data->scl_gpio, config->scl.pin,
			GPIO_PULL_UP | GPIO_OPEN_DRAIN | GPIO_OUTPUT | GPIO_INPUT);
	esp_rom_gpio_matrix_out(config->scl.pin, config->scl.sig_out, 0, 0);
	esp_rom_gpio_matrix_in(config->scl.pin, config->scl.sig_in, 0);

	return ret;
}

/* Some slave device will die by accident and keep the SDA in low level,
 * in this case, master should send several clock to make the slave release the bus.
 * Slave mode of ESP32 might also get in wrong state that held the SDA low,
 * in this case, master device could send a stop signal to make esp32 slave release the bus.
 **/
static void IRAM_ATTR i2c_master_clear_bus(const struct device *dev)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

#ifndef SOC_I2C_SUPPORT_HW_CLR_BUS
	const struct i2c_esp32_config *config = dev->config;
	const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; /* use standard 100kHz data rate */
	int i = 0;
	gpio_pin_t scl_io = config->scl.pin;
	gpio_pin_t sda_io = config->sda.pin;

	gpio_pin_configure(data->scl_gpio, scl_io, GPIO_OUTPUT | GPIO_OPEN_DRAIN);
	gpio_pin_configure(data->sda_gpio, sda_io, GPIO_OUTPUT | GPIO_OPEN_DRAIN | GPIO_INPUT);
	/* If a SLAVE device was in a read operation when the bus was interrupted, */
	/* the SLAVE device is controlling SDA. If the slave is sending a stream of ZERO bytes, */
	/* it will only release SDA during the  ACK bit period. So, this reset code needs */
	/* to synchronize the bit stream with either the ACK bit, or a 1 bit to correctly */
	/* generate a STOP condition. */
	gpio_pin_set(data->scl_gpio, scl_io, 0);
	gpio_pin_set(data->sda_gpio, sda_io, 1);
	esp_rom_delay_us(scl_half_period);
	while (!gpio_pin_get(data->sda_gpio, sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) {
		gpio_pin_set(data->scl_gpio, scl_io, 1);
		esp_rom_delay_us(scl_half_period);
		gpio_pin_set(data->scl_gpio, scl_io, 0);
		esp_rom_delay_us(scl_half_period);
	}
	gpio_pin_set(data->sda_gpio, sda_io, 0); /* setup for STOP */
	gpio_pin_set(data->scl_gpio, scl_io, 1);
	esp_rom_delay_us(scl_half_period);
	gpio_pin_set(data->sda_gpio, sda_io, 1); /* STOP, SDA low -> high while SCL is HIGH */
	i2c_esp32_config_pin(dev);
#else
	i2c_hal_master_clr_bus(&data->hal);
#endif
	i2c_hal_update_config(&data->hal);
}

static void IRAM_ATTR i2c_hw_fsm_reset(const struct device *dev)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

#ifndef SOC_I2C_SUPPORT_HW_FSM_RST
	const struct i2c_esp32_config *config = dev->config;
	int scl_low_period, scl_high_period;
	int scl_start_hold, scl_rstart_setup;
	int scl_stop_hold, scl_stop_setup;
	int sda_hold, sda_sample;
	int timeout;
	uint8_t filter_cfg;

	i2c_hal_get_scl_timing(&data->hal, &scl_high_period, &scl_low_period);
	i2c_hal_get_start_timing(&data->hal, &scl_rstart_setup, &scl_start_hold);
	i2c_hal_get_stop_timing(&data->hal, &scl_stop_setup, &scl_stop_hold);
	i2c_hal_get_sda_timing(&data->hal, &sda_sample, &sda_hold);
	i2c_hal_get_tout(&data->hal, &timeout);
	i2c_hal_get_filter(&data->hal, &filter_cfg);

	/* to reset the I2C hw module, we need re-enable the hw */
	clock_control_off(config->clock_dev, config->clock_subsys);
	i2c_master_clear_bus(dev);
	clock_control_on(config->clock_dev, config->clock_subsys);

	i2c_hal_master_init(&data->hal, config->index);
	i2c_hal_disable_intr_mask(&data->hal, I2C_LL_INTR_MASK);
	i2c_hal_clr_intsts_mask(&data->hal, I2C_LL_INTR_MASK);
	i2c_hal_set_scl_timing(&data->hal, scl_high_period, scl_low_period);
	i2c_hal_set_start_timing(&data->hal, scl_rstart_setup, scl_start_hold);
	i2c_hal_set_stop_timing(&data->hal, scl_stop_setup, scl_stop_hold);
	i2c_hal_set_sda_timing(&data->hal, sda_sample, sda_hold);
	i2c_hal_set_tout(&data->hal, timeout);
	i2c_hal_set_filter(&data->hal, filter_cfg);
#else
	i2c_hal_master_fsm_rst(&data->hal);
	i2c_master_clear_bus(dev);
#endif
	i2c_hal_update_config(&data->hal);
}

static int i2c_esp32_recover(const struct device *dev)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

	k_sem_take(&data->transfer_sem, K_FOREVER);
	i2c_hw_fsm_reset(dev);
	k_sem_give(&data->transfer_sem);

	return 0;
}

static int i2c_esp32_configure(const struct device *dev, uint32_t dev_config)
{
	const struct i2c_esp32_config *config = dev->config;
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

	if (!(dev_config & I2C_MODE_MASTER)) {
		LOG_ERR("Only I2C Master mode supported.");
		return -ENOTSUP;
	}

	data->dev_config = dev_config;

	i2c_trans_mode_t tx_mode = I2C_DATA_MODE_MSB_FIRST;
	i2c_trans_mode_t rx_mode = I2C_DATA_MODE_MSB_FIRST;

	if (config->mode.tx_lsb_first) {
		tx_mode = I2C_DATA_MODE_LSB_FIRST;
	}

	if (config->mode.rx_lsb_first) {
		rx_mode = I2C_DATA_MODE_LSB_FIRST;
	}

	i2c_hal_master_init(&data->hal, config->index);
	i2c_hal_set_data_mode(&data->hal, tx_mode, rx_mode);
	i2c_hal_set_filter(&data->hal, I2C_FILTER_CYC_NUM_DEF);
	i2c_hal_update_config(&data->hal);

	if (config->bitrate == 0) {
		LOG_ERR("Error configuring I2C speed.");
		return -ENOTSUP;
	}

	i2c_hal_set_bus_timing(&data->hal, config->bitrate, i2c_get_clk_src(config->bitrate));
	i2c_hal_update_config(&data->hal);

	return 0;
}

static void IRAM_ATTR i2c_esp32_reset_fifo(const struct device *dev)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

	/* reset fifo buffers */
	i2c_hal_txfifo_rst(&data->hal);
	i2c_hal_rxfifo_rst(&data->hal);
}

static int IRAM_ATTR i2c_esp32_transmit(const struct device *dev)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

	/* start the transfer */
	i2c_hal_update_config(&data->hal);
	i2c_hal_trans_start(&data->hal);

	int ret = k_sem_take(&data->cmd_sem, K_MSEC(I2C_TRANSFER_TIMEOUT_MSEC));

	if (ret != 0) {
		/* If the I2C slave is powered off or the SDA/SCL is */
		/* connected to ground, for example, I2C hw FSM would get */
		/* stuck in wrong state, we have to reset the I2C module in this case. */
		i2c_hw_fsm_reset(dev);
		return -ETIMEDOUT;
	}

	if (data->status == I2C_STATUS_TIMEOUT) {
		i2c_hw_fsm_reset(dev);
		ret = -ETIMEDOUT;
	} else if (data->status == I2C_STATUS_ACK_ERROR) {
		ret = -EFAULT;
	} else {
		ret = 0;
	}

	return ret;
}

static void IRAM_ATTR i2c_esp32_write_addr(const struct device *dev, uint16_t addr)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	uint8_t addr_len = 1;
	uint8_t addr_byte = addr & 0xFF;

	i2c_hw_cmd_t cmd = {
		.op_code = I2C_LL_CMD_RESTART
	};

	/* write re-start command */
	i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);

	/* write address value in tx buffer */
	i2c_hal_write_txfifo(&data->hal, &addr_byte, 1);
	if (data->dev_config & I2C_ADDR_10_BITS) {
		addr_byte = (addr >> 8) & 0xFF;
		i2c_hal_write_txfifo(&data->hal, &addr_byte, 1);
		addr_len++;
	}

	cmd = (i2c_hw_cmd_t) {
		.op_code = I2C_LL_CMD_WRITE,
		.ack_en = true,
		.byte_num = addr_len,
	};

	i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);
}

static int IRAM_ATTR i2c_esp32_read_msg(const struct device *dev,
	struct i2c_msg *msg, uint16_t addr)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	uint8_t rd_filled = 0;
	uint8_t *read_pr = NULL;
	int ret = 0;

	/* reset command index and set status as read operation */
	data->cmd_idx = 0;
	data->status = I2C_STATUS_READ;

	i2c_hw_cmd_t cmd = {
		.op_code = I2C_LL_CMD_READ
	};

	i2c_hw_cmd_t hw_end_cmd = {
		.op_code = I2C_LL_CMD_END,
	};

	/* Set the R/W bit to R */
	addr |= BIT(0);

	if (msg->flags & I2C_MSG_RESTART) {
		/* write restart command and address */
		i2c_esp32_write_addr(dev, addr);
	}

	while (msg->len) {
		rd_filled = (msg->len > SOC_I2C_FIFO_LEN) ? SOC_I2C_FIFO_LEN : (msg->len - 1);
		read_pr = msg->buf;
		msg->len -= rd_filled;

		if (rd_filled) {
			cmd = (i2c_hw_cmd_t) {
				.op_code = I2C_LL_CMD_READ,
				.ack_en = false,
				.ack_val = 0,
				.byte_num = rd_filled
			};

			i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);
		}

		/* I2C master won't acknowledge the last byte read from the
		 * slave device. Divide the read command in two segments as
		 * recommended by the ESP32 Technical Reference Manual.
		 */
		if (msg->len == 1) {
			cmd = (i2c_hw_cmd_t)  {
				.op_code = I2C_LL_CMD_READ,
				.byte_num = 1,
				.ack_val = 1,
			};
			msg->len = 0;
			rd_filled++;
			i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);
		}

		if (msg->len == 0) {
			cmd = (i2c_hw_cmd_t)  {
				.op_code = I2C_LL_CMD_STOP,
				.byte_num = 0,
				.ack_val = 0,
				.ack_en = 0
			};
			i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);
		}

		i2c_hal_write_cmd_reg(&data->hal, hw_end_cmd, data->cmd_idx++);
		i2c_hal_enable_master_rx_it(&data->hal);

		ret = i2c_esp32_transmit(dev);
		if (ret < 0) {
			LOG_ERR("I2C transfer error: %d", ret);
			return ret;
		}

		i2c_hal_read_rxfifo(&data->hal, msg->buf, rd_filled);
		msg->buf += rd_filled;

		/* reset fifo read pointer */
		data->cmd_idx = 0;
	}

	return 0;
}

static int IRAM_ATTR i2c_esp32_write_msg(const struct device *dev,
		struct i2c_msg *msg, uint16_t addr)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	uint8_t wr_filled = 0;
	uint8_t *write_pr = NULL;
	int ret = 0;

	/* reset command index and set status as write operation */
	data->cmd_idx = 0;
	data->status = I2C_STATUS_WRITE;

	i2c_hw_cmd_t cmd = {
		.op_code = I2C_LL_CMD_WRITE,
		.ack_en = true
	};

	i2c_hw_cmd_t hw_end_cmd = {
		.op_code = I2C_LL_CMD_END,
	};

	if (msg->flags & I2C_MSG_RESTART) {
		/* write restart command and address */
		i2c_esp32_write_addr(dev, addr);
	}

	for (;;) {
		wr_filled = (msg->len > SOC_I2C_FIFO_LEN) ? SOC_I2C_FIFO_LEN : msg->len;
		write_pr = msg->buf;
		msg->buf += wr_filled;
		msg->len -= wr_filled;
		cmd.byte_num = wr_filled;

		if (wr_filled > 0) {
			i2c_hal_write_txfifo(&data->hal, write_pr, wr_filled);
			i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx++);
			i2c_hal_write_cmd_reg(&data->hal, hw_end_cmd, data->cmd_idx++);

			i2c_hal_enable_master_tx_it(&data->hal);

			ret = i2c_esp32_transmit(dev);
			if (ret < 0) {
				LOG_ERR("I2C transfer error: %d", ret);
				return ret;
			}

			data->cmd_idx = 0;
		}

		if (msg->len == 0) {
			break;
		}
	}

	/* add stop command in a new transmission */
	if (msg->len == 0 && (msg->flags & I2C_MSG_STOP)) {
		cmd = (i2c_hw_cmd_t) {
			.op_code = I2C_LL_CMD_STOP,
			.ack_en = false,
			.byte_num = 0
		};
		i2c_hal_write_cmd_reg(&data->hal, cmd, data->cmd_idx);
		i2c_hal_enable_master_tx_it(&data->hal);
		ret = i2c_esp32_transmit(dev);
		if (ret < 0) {
			LOG_ERR("I2C transfer error: %d", ret);
			return ret;
		}
	}

	return 0;
}

static int IRAM_ATTR i2c_esp32_transfer(const struct device *dev, struct i2c_msg *msgs,
			      uint8_t num_msgs, uint16_t addr)
{
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	struct i2c_msg *current, *next;
	int ret = 0;

	if (!num_msgs) {
		return 0;
	}

	/* Check for validity of all messages before transfer */
	current = msgs;

	/* Add restart flag on first message to send start event */
	current->flags |= I2C_MSG_RESTART;

	for (int k = 1; k <= num_msgs; k++) {
		if (k < num_msgs) {
			next = current + 1;

			/* messages of different direction require restart event */
			if ((current->flags & I2C_MSG_RW_MASK) != (next->flags & I2C_MSG_RW_MASK)) {
				if (!(next->flags & I2C_MSG_RESTART)) {
					ret = -EINVAL;
					break;
				}
			}

			/* check if there is any stop event in the middle of the transaction */
			if (current->flags & I2C_MSG_STOP) {
				ret = -EINVAL;
				break;
			}
		} else {
			/* make sure the last message contains stop event */
			current->flags |= I2C_MSG_STOP;
		}

		current++;
	}

	if (ret) {
		return ret;
	}

	k_sem_take(&data->transfer_sem, K_FOREVER);

	/* Mask out unused address bits, and make room for R/W bit */
	addr &= BIT_MASK(data->dev_config & I2C_ADDR_10_BITS ? 10 : 7);
	addr <<= 1;

	for (; num_msgs > 0; num_msgs--, msgs++) {

		if (data->status == I2C_STATUS_TIMEOUT || i2c_hal_is_bus_busy(&data->hal)) {
			i2c_hw_fsm_reset(dev);
		}

		/* reset all fifo buffer before start */
		i2c_esp32_reset_fifo(dev);

		/* These two interrupts some times can not be cleared when the FSM gets stuck. */
		/* So we disable them when these two interrupt occurs and re-enable them here. */
		i2c_hal_disable_intr_mask(&data->hal, I2C_LL_INTR_MASK);
		i2c_hal_clr_intsts_mask(&data->hal, I2C_LL_INTR_MASK);

		if ((msgs->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) {
			ret = i2c_esp32_read_msg(dev, msgs, addr);
		} else {
			ret = i2c_esp32_write_msg(dev, msgs, addr);
		}

		if (ret < 0) {
			break;
		}
	}

	k_sem_give(&data->transfer_sem);

	return ret;
}

static void IRAM_ATTR i2c_esp32_isr(void *arg)
{
	struct device *dev = (struct device *)arg;
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;
	i2c_intr_event_t evt_type = I2C_INTR_EVENT_ERR;

	if (data->status == I2C_STATUS_WRITE) {
		i2c_hal_master_handle_tx_event(&data->hal, &evt_type);
	} else if (data->status == I2C_STATUS_READ) {
		i2c_hal_master_handle_rx_event(&data->hal, &evt_type);
	}

	if (evt_type == I2C_INTR_EVENT_NACK) {
		data->status = I2C_STATUS_ACK_ERROR;
	} else if (evt_type == I2C_INTR_EVENT_TOUT) {
		data->status = I2C_STATUS_TIMEOUT;
	} else if (evt_type == I2C_INTR_EVENT_ARBIT_LOST) {
		data->status = I2C_STATUS_TIMEOUT;
	} else if (evt_type == I2C_INTR_EVENT_TRANS_DONE) {
		data->status = I2C_STATUS_DONE;
	}

	k_sem_give(&data->cmd_sem);
}

static int i2c_esp32_init(const struct device *dev);

static const struct i2c_driver_api i2c_esp32_driver_api = {
	.configure = i2c_esp32_configure,
	.transfer = i2c_esp32_transfer,
	.recover_bus = i2c_esp32_recover
};

static int IRAM_ATTR i2c_esp32_init(const struct device *dev)
{
	const struct i2c_esp32_config *config = dev->config;
	struct i2c_esp32_data *data = (struct i2c_esp32_data *const)(dev)->data;

	if (config->scl.gpio_name == NULL || config->sda.gpio_name == NULL) {
		LOG_ERR("Failed to get GPIO device");
		return -EINVAL;
	}

	data->scl_gpio = device_get_binding(config->scl.gpio_name);
	if (!data->scl_gpio) {
		LOG_ERR("Failed to get SCL GPIO device");
		return -EINVAL;
	}

	data->sda_gpio = device_get_binding(config->sda.gpio_name);
	if (!data->sda_gpio) {
		LOG_ERR("Failed to get SDA GPIO device");
		return -EINVAL;
	}

	int ret = i2c_esp32_config_pin(dev);

	if (ret < 0) {
		LOG_ERR("Failed to configure I2C pins");
		return -EINVAL;
	}

	clock_control_on(config->clock_dev, config->clock_subsys);

	esp_intr_alloc(config->irq_source, 0, i2c_esp32_isr, (void *)dev, NULL);

	return i2c_esp32_configure(dev, config->default_config);
}

#define GPIO0_NAME COND_CODE_1(DT_NODE_HAS_STATUS(DT_NODELABEL(gpio0), okay), \
			     (DT_LABEL(DT_INST(0, espressif_esp32_gpio))), (NULL))
#define GPIO1_NAME COND_CODE_1(DT_NODE_HAS_STATUS(DT_NODELABEL(gpio1), okay), \
			     (DT_LABEL(DT_INST(1, espressif_esp32_gpio))), (NULL))

#define DT_I2C_ESP32_GPIO_NAME(idx, pin) ( \
	DT_INST_PROP(idx, pin) < 32 ? GPIO0_NAME : GPIO1_NAME)

#define I2C_ESP32_FREQUENCY(bitrate)				       \
	 (bitrate == I2C_BITRATE_STANDARD ? KHZ(100)	       \
	: bitrate == I2C_BITRATE_FAST     ? KHZ(400)	       \
	: bitrate == I2C_BITRATE_FAST_PLUS  ? MHZ(1) : 0)
#define I2C_FREQUENCY(idx)						       \
	I2C_ESP32_FREQUENCY(DT_INST_PROP(idx, clock_frequency))

#define ESP32_I2C_INIT(idx)		\
	static struct i2c_esp32_data i2c_esp32_data_##idx = {		  \
		.hal = {	\
			.dev = (i2c_dev_t *) DT_REG_ADDR(DT_NODELABEL(i2c##idx)),	\
		},	\
		.cmd_sem = Z_SEM_INITIALIZER(                            \
			i2c_esp32_data_##idx.cmd_sem, 0, 1),                 \
		.transfer_sem = Z_SEM_INITIALIZER(                        \
			i2c_esp32_data_##idx.transfer_sem, 1, 1)		      \
	};							\
								\
	static const struct i2c_esp32_config i2c_esp32_config_##idx = {	       \
	.index = idx, \
	.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \
	.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset), \
	.scl = {	\
		.gpio_name = DT_I2C_ESP32_GPIO_NAME(idx, scl_pin),	\
		.sig_out = I2CEXT##idx##_SCL_OUT_IDX,	\
		.sig_in = I2CEXT##idx##_SCL_IN_IDX,	\
		.pin = DT_INST_PROP(idx, scl_pin), \
	},	\
	.sda = {	\
		.gpio_name = DT_I2C_ESP32_GPIO_NAME(idx, sda_pin),	\
		.sig_out = I2CEXT##idx##_SDA_OUT_IDX,	\
		.sig_in = I2CEXT##idx##_SDA_IN_IDX,	\
		.pin = DT_INST_PROP(idx, sda_pin), \
	},	\
	.mode = { \
		.tx_lsb_first = DT_INST_PROP(idx, tx_lsb), \
		.rx_lsb_first = DT_INST_PROP(idx, rx_lsb), \
	}, \
	.irq_source = ETS_I2C_EXT##idx##_INTR_SOURCE,	\
	.bitrate = I2C_FREQUENCY(idx),	\
	.default_config = I2C_MODE_MASTER,				\
	};								       \
	I2C_DEVICE_DT_DEFINE(DT_NODELABEL(i2c##idx),					       \
		      i2c_esp32_init,					       \
		      NULL,				       \
		      &i2c_esp32_data_##idx,				       \
		      &i2c_esp32_config_##idx,				       \
		      POST_KERNEL,					       \
		      CONFIG_I2C_INIT_PRIORITY,	       \
		      &i2c_esp32_driver_api); \

#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c0), okay)
ESP32_I2C_INIT(0);
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay)
ESP32_I2C_INIT(1);
#endif
